﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using SSE554_Proj1.Entity;

namespace SSE554_Proj1
{
    class Program
    {
        static readonly object locker = new object();
        static int tick;

        static void Main(string[] args)
        {
            string m1 = "\nType 'm' for multithread or 's' for sequential run then press Enter. " +
                "\nType '+' anywhere in the text to quit:\n";
            string str;
            Console.WriteLine(m1);
            Timer tmr = new Timer(Tick, "tick...", 0, 1000);
            ATS_Controller atsNonSync = new ATS_Controller();
            ATS_Controller atsSync = atsNonSync.Synchronized(atsNonSync);

            Signal_Generator sigGen = new Signal_Generator();
            Oscilloscope oScope = new Oscilloscope();
            Power_Supply pSupply = new Power_Supply();
            Relays_Card rCard = new Relays_Card();
            Multimeter meter = new Multimeter();
            Digital_Module dModule = new Digital_Module();
            do
            {
                str = Console.ReadLine();
                try
                {
                    if (str == "m")
                    {
                        tick = 1;
                        Task t1 = new Task(() => atsNonSync.Online_Test(sigGen, atsSync));
                        Task t2 = new Task(() => atsNonSync.Online_Test(oScope, atsSync));
                        Task t3 = new Task(() => atsNonSync.Online_Test(pSupply, atsSync));
                        Task t4 = new Task(() => atsNonSync.Online_Test(rCard, atsSync));
                        Task t5 = new Task(() => atsNonSync.Online_Test(meter, atsSync));
                        Task t6 = new Task(() => atsNonSync.Online_Test(dModule, atsSync));
                        t1.Start();
                        if (oScope.BusType == Bus.Message)
                        {
                            t2.Start();
                        }
                        else
                        {
                            t2 = t1.ContinueWith((antecedent) => atsNonSync.Online_Test(oScope, atsSync));
                        }
                        t3.Start();
                        t4.Start();
                        t5.Start();

                        Task tFail1 = t1.ContinueWith((antecedent) => Console.WriteLine(antecedent.Exception.InnerException.Message), TaskContinuationOptions.OnlyOnFaulted);
                        var t7 = t1.ContinueWith<Tuple<int, string>>((antecedent) => atsSync.SelfTest(sigGen), TaskContinuationOptions.NotOnFaulted);

                        Task tFail2 = t2.ContinueWith((antecedent) => Console.WriteLine(antecedent.Exception.InnerException.Message), TaskContinuationOptions.OnlyOnFaulted);
                        var t8 = t2.ContinueWith<Tuple<int, string>>((antecedent) => atsSync.SelfTest(oScope), TaskContinuationOptions.NotOnFaulted);

                        Task tFail3 = t3.ContinueWith((antecedent) => Console.WriteLine(antecedent.Exception.InnerException.Message), TaskContinuationOptions.OnlyOnFaulted);
                        var t9 = t3.ContinueWith<Tuple<int, string>>((antecedent) => atsSync.SelfTest(pSupply), TaskContinuationOptions.NotOnFaulted);

                        Task tFail4 = t4.ContinueWith((antecedent) => Console.WriteLine(antecedent.Exception.InnerException.Message), TaskContinuationOptions.OnlyOnFaulted);
                        var t10 = t4.ContinueWith<Tuple<int, string>>((antecedent) => atsSync.SelfTest(rCard), TaskContinuationOptions.NotOnFaulted);

                        Task tFail5 = t5.ContinueWith((antecedent) => Console.WriteLine(antecedent.Exception.InnerException.Message), TaskContinuationOptions.OnlyOnFaulted);
                        var t11 = t5.ContinueWith<Tuple<int, string>>((antecedent) => atsSync.SelfTest(meter), TaskContinuationOptions.NotOnFaulted);

                        //FOR EXCEPTION EXAMPLE
                        //t6 = t10.ContinueWith((antecedent) => atsNonSync.Online_Test(dModule, atsNonSync));
                        t6 = t10.ContinueWith((antecedent) => atsNonSync.Online_Test(dModule, atsSync));

                        Task tFail6 = t6.ContinueWith((antecedent) => Console.WriteLine(antecedent.Exception.InnerException.Message), TaskContinuationOptions.OnlyOnFaulted);
                        var t12 = t6.ContinueWith<Tuple<int, string>>((antecedent) => atsSync.SelfTest(dModule), TaskContinuationOptions.NotOnFaulted);

                        t7.Wait();
                        t8.Wait();
                        t9.Wait();
                        t10.Wait();
                        t11.Wait();
                        t12.Wait();
                        if (t7.Result.Item1 == 1)
                            Console.WriteLine(t7.Result.Item2);
                        if (t8.Result.Item1 == 1)
                            Console.WriteLine(t8.Result.Item2);
                        if (t9.Result.Item1 == 1)
                            Console.WriteLine(t9.Result.Item2);
                        if (t10.Result.Item1 == 1)
                            Console.WriteLine(t10.Result.Item2);
                        if (t11.Result.Item1 == 1)
                            Console.WriteLine(t11.Result.Item2);
                        if (t12.Result.Item1 == 1)
                            Console.WriteLine(t12.Result.Item2);
                    }
                    else if (str == "s")
                    {
                        tick = 1;
                        atsNonSync.Online_Test(sigGen, atsSync);
                        Tuple<int, string> tupSequential1 = atsNonSync.SelfTest(sigGen);
                        atsNonSync.Online_Test(oScope, atsSync);
                        Tuple<int, string> tupSequential2 = atsNonSync.SelfTest(oScope);
                        atsNonSync.Online_Test(pSupply, atsSync);
                        Tuple<int, string> tupSequential3 = atsNonSync.SelfTest(pSupply);
                        atsNonSync.Online_Test(rCard, atsSync);
                        Tuple<int, string> tupSequential4 = atsNonSync.SelfTest(rCard);
                        atsNonSync.Online_Test(meter, atsSync);
                        Tuple<int, string> tupSequential5 = atsNonSync.SelfTest(meter);
                        atsNonSync.Online_Test(dModule, atsSync);
                        Tuple<int, string> tupSequential6 = atsNonSync.SelfTest(dModule);
                        if (tupSequential1.Item1 == 1)
                            Console.WriteLine(tupSequential1.Item2);
                        if (tupSequential2.Item1 == 1)
                            Console.WriteLine(tupSequential2.Item2);
                        if (tupSequential3.Item1 == 1)
                            Console.WriteLine(tupSequential3.Item2);
                        if (tupSequential4.Item1 == 1)
                            Console.WriteLine(tupSequential4.Item2);
                        if (tupSequential5.Item1 == 1)
                            Console.WriteLine(tupSequential5.Item2);
                        if (tupSequential6.Item1 == 1)
                            Console.WriteLine(tupSequential6.Item2);

                    }
                    else
                        Console.WriteLine("Invalid key");
                }
                catch (OverflowException e)
                {
                    Console.WriteLine("{0} Value read = {1}.", e.Message, str);
                }
                catch (NullReferenceException e)
                {
                    Console.WriteLine("{0} Value read = {1}.", e.Message, str);
                }
                catch (AggregateException aex)
                {
                    Console.WriteLine(aex.InnerException.Message); 
                }
                finally
                {
                    Console.WriteLine("\nTotal Time Elapse {0}s", tick);
                    Console.WriteLine(m1);
                }

            } while (str != "+");
            tmr.Dispose();

            // demo1.DoThis();
            //if (!demo1.IsSynchronized) throw new UnsynchronizedException("Requires synchronization");
            //Console.ReadKey();
            
        }

        static void Tick(object data)
        {
            tick++;
        } 
    }
}
